#ifndef __UMBRA_GAME__
#define __UMBRA_GAME__

#include <zen/zen.hpp>

class GameController;
class GameModel;
class GameView;

#include "GameModel.hpp"
#include "GameView.hpp"
#include "GameController.hpp"

namespace umbra {

class UmbraGame: public zen::sys::Framer {
private:
	GameController* controller;
	GameModel* model;
	GameView* view;
	zen::video::Font mainFont;

public:
	UmbraGame() :
			Framer(60, 60), controller(NULL), model(NULL), view(NULL) {
	}
	~UmbraGame() {
	}

	int initialize();
	int update();
	int draw();
	int finalize();
};

int UmbraGame::initialize() {
	zen_call("UmbraGame.initialize");

	if (!zen::sys::Settings::initialize("data/settings")) {
		return zen::sys::FRAMER_EXIT;
	}

	if (!zen::sys::Window::open(zen::sys::Settings::get("window.title"), zen::sys::Settings::getInt("window.left"), zen::sys::Settings::getInt("window.top"),
			zen::sys::Settings::getInt("window.width"), zen::sys::Settings::getInt("window.height"), zen::sys::Settings::getBool("window.fullScreen"),
			zen::sys::Settings::getInt("window.glVersionMajor"), zen::sys::Settings::getInt("window.glVersionMinor"))) {
		return zen::sys::FRAMER_EXIT;
	}

	if (!zen::video::ShaderManager::loadShaders(zen::sys::Settings::get("paths.shaders"), zen::sys::Settings::get("resources.shadersConfig"))) {
		return zen::sys::FRAMER_EXIT;
	}

	/** SYSTEM INITIALIZATION **/
	controller = new GameController();
	model = new GameModel();
	view = new GameView();

	controller->initialize(model, view);

//	texture = zen::video::Textures::loadFile("data/textures/grass.bmp");

    int mainFontFace = zen::video::FontManager::loadFontFace("data/fonts/EleganTech.ttf");
    if (mainFontFace >= 0) {
		mainFont = zen::video::FontManager::createFont(mainFontFace, 10);
		zen::video::FontManager::freeFontFace(mainFontFace);
    }

	//controller->setGameModel(model);

//    if (!Scripting::initialize()) {
//        zen_log("Error: Failed to initialize scripting.");
//    } zen_else_log("Debug: Scripting initialized successfully.");

//    zen::sys::Event* event = new zen::sys::Event();
//    Scripting::call("kill", event);
//    std::cout << test;

//fonts.mainFont.loadJSLFile("Content/Fonts/default.jsl");
//zen_log("Debug: Fonts loaded successfully.");

//Models::initialize();

	/*this->modules = Module::getModules();
	 std::map<std::string, Module*>::iterator modIter = this->modules->find("arka_snake");
	 if (modIter != this->modules->end()) {
	 this->module = modIter->second;
	 if (this->module->load()) {
	 HexData::initialize(this->module->getHexDataFileName());
	 this->world = this->module->loadStartup();
	 if (this->world == NULL) {
	 zen_log("Error: Could not load startup world.");
	 return zen::sys::FRAMER_EXIT;
	 }
	 }
	 zen_log("Debug: Loaded default module \"arka_snake\".");
	 } else {
	 zen_log("Error: Could not load default module \"arka_snake\".");
	 return zen::sys::FRAMER_EXIT;
	 }
	 this->controller = new WorldController(this->world);
	 this->view = new WorldView(this->world);*/

	//jsl::Node* jsl = zen::sys::Resources::load("data/ciao");
	//jsl->path("heightMap[0][1]");

	//view->getCamera().position(0, -10, 0);
	view->getCamera().lookAt(glm::vec3(-10.0f, -10.0f, 10.0f), glm::vec3(5.0f, 5.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));

	/// -------------------------------------------------------------------------------------------
	return zen::sys::FRAMER_CONTINUE;
}

int UmbraGame::update() {
	zen_call("UmbraGame.update");
	zen::sys::Window::update();
	/// -------------------------------------------------------------------------------------------
	if (controller->update() != 0)
		return zen::sys::FRAMER_EXIT;

	/// -------------------------------------------------------------------------------------------
	return zen::sys::FRAMER_CONTINUE;
}

int UmbraGame::draw() {
	zen_call("UmbraGame.draw");
	zen::video::Graphics::clear(true, true);
	zen::video::Graphics::setModelView(glm::mat4());

	/// --- 3D ------------------------------------------------------------------------------------
	zen::video::Graphics::setProjection(glm::view3DMatrix(view->getCamera().lookAt(), zen::sys::Window::getAspectRatio(), 1.0f, 1.0f, 1000.0f));
	zen::video::Enable::depthTest();
	
	zen::video::Drawing::setColor(255, 0, 0, 255);
	zen::video::Primitives::cube(glm::scale(100.0f, 0.1f, 0.1f));
	zen::video::Drawing::setColor(0, 255, 0, 255);
	zen::video::Primitives::cube(glm::scale(0.1f, 100.0f, 0.1f));
	zen::video::Drawing::setColor(0, 0, 255, 255);
	zen::video::Primitives::cube(glm::scale(0.1f, 0.1f, 100.0f));
	zen::video::Drawing::setColor(255, 255, 255, 255);
	zen::video::Primitives::cube(glm::scale(0.2f, 0.2f, 0.2f));

	zen::video::Enable::texture2D();
		
	this->view->draw();

	zen::video::Disable::texture2D();
	
	zen::video::ShaderManager::useDefault();


	/// --- 2D ------------------------------------------------------------------------------------
	zen::video::Graphics::setProjection(glm::view2DMatrix(0.0f, 0.0f, (float)zen::sys::Window::getWindowWidth(), (float)zen::sys::Window::getWindowHeight(), -1.0f, 100.0f));
	zen::video::Disable::depthTest();
	
	zen::video::Enable::blend();
	zen::video::Enable::texture2D();

	zen::video::Drawing::setColor(255, 255, 0, 255);
	zen::video::Drawing::drawText(mainFont, "UPS: " + boost::lexical_cast<std::string>(this->getRealUPS()) + "   DPS: " + boost::lexical_cast<std::string>(this->getRealDPS()), 10, 30);

	zen::video::Disable::blend();
	zen::video::Disable::texture2D();

	zen::video::Drawing::setColor(255, 0, 255, 255);
	zen::video::Drawing::drawLine((float)zen::sys::Window::mouseX(), 0.0f, (float)zen::sys::Window::mouseX(), (float)zen::sys::Window::getWindowHeight(), 0.0f);
	zen::video::Drawing::drawLine(0.0f, (float)zen::sys::Window::mouseY(), (float)zen::sys::Window::getWindowWidth(), (float)zen::sys::Window::mouseY(), 0.0f);

	/// -------------------------------------------------------------------------------------------
	zen::sys::Window::draw();
	return zen::sys::FRAMER_CONTINUE;
}

int UmbraGame::finalize() {
	zen_call("UmbraGame.finalize");
	/// -------------------------------------------------------------------------------------------

	zen_log(zen::video::Graphics::getErrorString());

	/// -------------------------------------------------------------------------------------------
	zen::sys::Window::close();
	return zen::sys::FRAMER_CONTINUE;
}

} // namepace umbra

#endif
